package at.ac.univie.zsu.aguataplan.ui;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileFilter;

import at.ac.univie.zsu.aguataplan.domain.Game;
import at.ac.univie.zsu.aguataplan.domain.Team;
import at.ac.univie.zsu.aguataplan.domain.Video;
import at.ac.univie.zsu.aguataplan.exception.DatabaseException;
import at.ac.univie.zsu.aguataplan.exception.LogicException;
import at.ac.univie.zsu.aguataplan.exception.VideoHandlingException;
import at.ac.univie.zsu.aguataplan.property.GeneralProperties;
import at.ac.univie.zsu.aguataplan.property.I18nProperties;
import at.ac.univie.zsu.aguataplan.property.SystemProperties;
import at.ac.univie.zsu.aguataplan.service.GameManager;
import at.ac.univie.zsu.aguataplan.service.TeamManager;
import at.ac.univie.zsu.aguataplan.ui.template.IDialogListEntry;
import at.ac.univie.zsu.aguataplan.ui.template.ListEntryPanel;
import at.ac.univie.zsu.aguataplan.util.Constants;
import at.ac.univie.zsu.aguataplan.video.VideoService;

/**
 * @author gerry
 * 
 */
public class DialogGame extends JDialog implements UIConstants, Constants, ProgressListener {

	private static final long serialVersionUID = 1L;

	private JFrame parent;
	private GeneralProperties generalProperties;
	private I18nProperties i18nProp;
	private SystemProperties systemProp;

	private TeamManager teamManager;
	private GameManager gameManager;
	private VideoService videoService;

	private JFileChooser fileChooser;
	private DialogWait dialogWait;
	private String fileName;
	private String dirName;

	private int done;

	// ----------------------------------------------------
	// CONSTRUCTOR
	// ----------------------------------------------------

	public DialogGame(MainWindow parent, GeneralProperties generalProperties) {
		super(parent, true);

		this.parent = parent;
		this.generalProperties = generalProperties;
		this.i18nProp = generalProperties.getI18nProperties();
		this.systemProp = generalProperties.getSystemProperties();
		this.teamManager = parent.getServices().getTeamManager();
		this.gameManager = parent.getServices().getGameManager();
		this.videoService = parent.getServices().getVideoService();

		videoService.registerProgressListener(DialogGame.this);

		fileChooser = new JFileChooser();
		fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
		fileChooser.setFileFilter(new FileFilter() {

			@Override
			public String getDescription() {
				return i18nProp.getString(VIDEO_OPEN_DESCRIPTION);
			}

			@Override
			public boolean accept(File f) {
				return f.isDirectory() || f.getName().toLowerCase().endsWith(".avi");
			}
		});
		fileChooser.setAcceptAllFileFilterUsed(false);
		// dialogWait = new DialogWait(this, generalProperties, true);

		this.setLayout(null);
		setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
		setLocationByPlatform(true);
		setSize(SPACING + PANEL_SIZE_X_ENTRY + SPACING + PANEL_SIZE_X_ENTRY + SPACING + SPACING, SPACING
				+ PANEL_SIZE_Y_ENTRY + SPACING + DIALOG_SIZE_Y_HEADER);
		setTitle(i18nProp.getString(GAME_HEADER));
		setResizable(false);

		addEntries();

	}

	// ----------------------------------------------------
	// METHODS
	// ----------------------------------------------------

	@Override
	public synchronized void setProgress(int value) {
		dialogWait.setProgressValue(value);
	}

	public GeneralProperties getGeneralProperties() {
		return this.generalProperties;
	}

	private void addEntries() {
		// game panel
		final ListEntryPanel gamePanel = new ListEntryPanel(this, generalProperties, new IDialogListEntry() {

			@Override
			public List<Date> selectDate(Object obj) {
				Game game = (Game) obj;

				List<Date> list = new ArrayList<Date>();

				list.add(game.getCalDate());

				return list;
			}

			@Override
			public List<Integer> selectCombo(Object obj) {
				Game game = (Game) obj;

				List<Integer> list = null;

				Team team1 = game.getRefTeam1();
				Team team2 = game.getRefTeam2();

				try {
					Integer pos1 = teamManager.getTeamListPosition(team1.getId());
					Integer pos2 = teamManager.getTeamListPosition(team2.getId());
					list = new ArrayList<Integer>();
					list.add(pos1);
					list.add(pos2);

				} catch (DatabaseException e) {
					JOptionPane.showMessageDialog(DialogGame.this, i18nProp.getString(EX_GAME_LIST_DESC),
							i18nProp.getString(EX_GAME), JOptionPane.ERROR_MESSAGE);
				}

				return list;
			}

			@Override
			public List<String> select(Object obj) {
				Game game = (Game) obj;
				List<String> list = new ArrayList<String>();
				list.add(new String(game.getDescription()));
				list.add(new String(game.getGameResult()));
				return list;
			}

			@Override
			public Object merge(Object obj, List<String> list, List<Object> combos, List<Date> dates) {
				Game game = (Game) obj;

				game.setDescription(list.get(0));
				game.setGameResult(list.get(1));
				game.setRefTeam1((Team) combos.get(0));
				game.setRefTeam2((Team) combos.get(1));
				game.setCalDate(dates.get(0));

				Game g = null;

				try {
					g = gameManager.mergeGame(game);
				} catch (DatabaseException e) {
					JOptionPane.showMessageDialog(DialogGame.this, i18nProp.getString(EX_GAME_SAVE_DESC),
							i18nProp.getString(EX_GAME), JOptionPane.ERROR_MESSAGE);
				}

				return g;
			}

			@Override
			public List<List<?>> initCombo() {
				List<List<?>> l = null;

				List<Team> teams;
				try {
					teams = teamManager.getTeamList();
					l = new ArrayList<List<?>>();
					l.add(teams);
					l.add(teams);
				} catch (DatabaseException e) {
					JOptionPane.showMessageDialog(DialogGame.this, i18nProp.getString(EX_GAME_LIST_DESC),
							i18nProp.getString(EX_GAME), JOptionPane.ERROR_MESSAGE);
				}
				return l;
			}

			@Override
			public List<?> initText() {
				List<Game> games = null;
				try {
					games = gameManager.getGameList();
				} catch (DatabaseException e) {
					JOptionPane.showMessageDialog(DialogGame.this, i18nProp.getString(EX_GAME_LIST_DESC),
							i18nProp.getString(EX_GAME), JOptionPane.ERROR_MESSAGE);
				}
				return games;
			}

			@Override
			public Object delete(Object obj) {
				Game game = (Game) obj;

				try {
					gameManager.deleteGame(game.getId());
				} catch (DatabaseException e) {
					JOptionPane.showMessageDialog(DialogGame.this, i18nProp.getString(EX_GAME_DELETE_DESC),
							i18nProp.getString(EX_GAME), JOptionPane.ERROR_MESSAGE);
					return null;
				}

				return game;
			}

			@Override
			public Object add(List<String> list, List<Object> combos, List<Date> dates) {

				Team t1 = (Team) combos.get(0);
				Team t2 = (Team) combos.get(1);

				Game game = null;

				try {
					game = gameManager.addGame(list.get(0), t1, t2, dates.get(0), list.get(1));

				} catch (DatabaseException e) {
					JOptionPane.showMessageDialog(DialogGame.this, i18nProp.getString(EX_TEAM_ADD_DESC),
							i18nProp.getString(EX_TEAM), JOptionPane.ERROR_MESSAGE);
				} catch (LogicException e) {
					JOptionPane.showMessageDialog(DialogGame.this, i18nProp.getString(EX_TEAM_ADD_DESC),
							i18nProp.getString(EX_TEAM), JOptionPane.ERROR_MESSAGE);
				}

				return game;
			}

			@Override
			public List<Date> initDate() {
				return null;
			}

		});
		List<String> listGame = new ArrayList<String>();
		listGame.add(new String(i18nProp.getString(TOURNAMENT_DESCRIPTION)));
		listGame.add(new String(i18nProp.getString(GAME_RESULT)));
		List<String> listComboGame = new ArrayList<String>();
		listComboGame.add(new String(i18nProp.getString(GAME_TEAM1)));
		listComboGame.add(new String(i18nProp.getString(GAME_TEAM2)));
		List<String> listDateGame = new ArrayList<String>();
		listDateGame.add(new String(i18nProp.getString(TOURNAMENT_DATE)));
		gamePanel.init(i18nProp.getString(GAME_BORDER), PANEL_SIZE_X_ENTRY, PANEL_SIZE_Y_ENTRY, listGame,
				listComboGame, listDateGame, new ArrayList<String>(), new ArrayList<ActionListener>());

		ListEntryPanel videoPanel = new ListEntryPanel(this, generalProperties, new IDialogListEntry() {

			@Override
			public List<Date> selectDate(Object obj) {
				return null;
			}

			@Override
			public List<Integer> selectCombo(Object obj) {
				return null;
			}

			@Override
			public List<String> select(Object obj) {
				Video video = (Video) obj;

				List<String> list = new ArrayList<String>();

				list.add(new String(video.getName()));
				list.add(new String(video.getDescription()));
				// list.add(new String(video.getVideoCodec()));
				// list.add(new String(video.getAudioCodec()));
				return list;
			}

			@Override
			public Object merge(Object obj, List<String> list, List<Object> combos, List<Date> dates) {
				Video video = (Video) obj;

				video.setName(list.get(0));
				video.setDescription(list.get(1));
				// video.setVideoCodec(list.get(2));
				// video.setAudioCodec(list.get(3));

				Video retVideo = null;

				try {
					retVideo = gameManager.mergeVideo(video);
				} catch (DatabaseException e1) {
					JOptionPane.showMessageDialog(DialogGame.this, i18nProp.getString(EX_GAME_SAVE_DESC),
							i18nProp.getString(EX_GAME), JOptionPane.ERROR_MESSAGE);
				}

				return retVideo;
			}

			@Override
			public List<?> initText() {
				Game game = (Game) gamePanel.getSelectedValueEntry();

				List<Video> list = null;
				if (game == null) {
					return null;
				}
				try {
					list = gameManager.getGameVideoList(game);
				} catch (DatabaseException e) {
					JOptionPane.showMessageDialog(DialogGame.this, i18nProp.getString(EX_GAME_LIST_DESC),
							i18nProp.getString(EX_GAME), JOptionPane.ERROR_MESSAGE);

				}
				return list;
			}

			@Override
			public List<Date> initDate() {
				return null;
			}

			@Override
			public List<List<?>> initCombo() {
				return null;
			}

			@Override
			public Object delete(Object obj) {
				Video video = (Video) obj;

				try {
					videoService.deleteVideo(video.getLocationPath());
				} catch (VideoHandlingException e1) {
					JOptionPane.showMessageDialog(DialogGame.this, i18nProp.getString(EX_GAME_DELETE_DESC),
							i18nProp.getString(EX_GAME), JOptionPane.ERROR_MESSAGE);
				}

				try {
					gameManager.deleteVideo(video.getRefTournament().getId(), video.getId());
				} catch (DatabaseException e) {
					JOptionPane.showMessageDialog(DialogGame.this, i18nProp.getString(EX_GAME_DELETE_DESC),
							i18nProp.getString(EX_GAME), JOptionPane.ERROR_MESSAGE);
					return null;
				}

				return video;
			}

			@Override
			public Object add(List<String> list, List<Object> combos, List<Date> dates) {
				Video video = new Video();
				video.setName(list.get(0));
				video.setDescription(list.get(1));

				Video retVideo = null;

				Game game = (Game) gamePanel.getSelectedValueEntry();

				// FIXME: should be in service but not in gui!!!

				dialogWait = new DialogWait(DialogGame.this, generalProperties, true);

				setUnDone();

				new Thread() {

					@Override
					public void run() {
						try {
							videoService.registerProgressListener(DialogGame.this);
							videoService.insertVideo(dirName, fileName);

							setDone();
							dialogWait.setVisible(false);
							dialogWait.dispose();
						} catch (VideoHandlingException e) {
							setError();
							dialogWait.setVisible(false);
							dialogWait.dispose();
							JOptionPane.showMessageDialog(DialogGame.this, i18nProp.getString(EX_GAME_VIDEO_DESC),
									i18nProp.getString(EX_GAME), JOptionPane.ERROR_MESSAGE);
						} finally {
							DialogGame.this.fileName = "";
							DialogGame.this.dirName = "";
						}
					}

				}.start();

				if (!isDone()) {
					// block event dispaching thread
					dialogWait.setVisible(true);
				}

				if (isError()) {
					return null;
				}

				String s = videoService.getVideoNameInserted();

				try {
					// retVideo = gameManager.addVideo(game, list.get(0),
					// list.get(1), s, 0, list.get(2), list.get(3));
					retVideo = gameManager.addVideo(game, list.get(0), list.get(1), s, 0, "", "");

				} catch (DatabaseException e) {
					JOptionPane.showMessageDialog(DialogGame.this, i18nProp.getString(EX_GAME_ADD_DESC),
							i18nProp.getString(EX_GAME), JOptionPane.ERROR_MESSAGE);
				}
				return retVideo;

			}
		});
		List<String> listVideo = new ArrayList<String>();
		listVideo.add(new String(i18nProp.getString(VIDEO_NAME)));
		listVideo.add(new String(i18nProp.getString(VIDEO_DESCRIPTION)));
		// listVideo.add(new String(i18nProp.getString(VIDEO_VIDEOCODEC)));
		// listVideo.add(new String(i18nProp.getString(VIDEO_AUDIOCODEC)));
		List<String> listButtonVideo = new ArrayList<String>();
		listButtonVideo.add(new String(i18nProp.getString(VIDEO_BUTTON_ADD)));
		List<ActionListener> listActionVideo = new ArrayList<ActionListener>();
		ActionListener al = new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				int ret = fileChooser.showOpenDialog(DialogGame.this);

				if (ret == JFileChooser.APPROVE_OPTION) {

					fileName = fileChooser.getSelectedFile().getName();
					dirName = fileChooser.getSelectedFile().getParent();

					System.out.println(fileName);
					System.out.println(dirName);

				}
			}
		};
		listActionVideo.add(al);
		videoPanel.init(i18nProp.getString(VIDEO_BORDER), PANEL_SIZE_X_ENTRY, PANEL_SIZE_Y_ENTRY, listVideo,
				new ArrayList<String>(), new ArrayList<String>(), listButtonVideo, listActionVideo);

		// set relationship
		gamePanel.addChild(videoPanel);
		videoPanel.addParent(gamePanel);

		// add to dialog
		gamePanel.setLocation(SPACING, SPACING);
		videoPanel.setLocation(SPACING + PANEL_SIZE_X_ENTRY + SPACING, SPACING);
		this.add(gamePanel);
		this.add(videoPanel);

		// finish init
		gamePanel.finishInit();
		videoPanel.finishInit();

	}

	private synchronized void setDone() {
		this.done = THREAD_DONE;
	}

	private synchronized void setUnDone() {
		this.done = THREAD_UNDONE;
	}

	private synchronized void setError() {
		this.done = THREAD_ERROR;
	}

	private synchronized boolean isDone() {
		if (this.done == THREAD_DONE) {
			return true;
		}
		return false;
	}

	private synchronized boolean isError() {
		if (this.done == THREAD_ERROR) {
			return true;
		}
		return false;
	}

}
